﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Core;
using UnityEditor;
using UnityEngine;

public class ABDistributionChecker
{
    private const string Dir = "b_ABDistribution"; //输出文件的目录

    private Action<string> OnFinish;

    private string m_ab_path = "";
    private string m_result_path = "";
    private string m_main_ab = "";

    private Dictionary<string, HashSet<string>> mBundleMap = new Dictionary<string, HashSet<string>>();

    public void StartCheck(string path, string platform, string abName, Action<string> func)
    {
        m_ab_path = Path.Combine(path, platform);
        m_result_path = Path.Combine(path, Dir);
        m_main_ab = abName;
        OnFinish = func;
        StartCheck();
    }

    private void StartCheck()
    {
        mBundleMap.Clear();

        if (!GenAssetMap(m_ab_path, m_main_ab))
        {
            return;
        }

        if (!Directory.Exists(m_result_path))
        {
            Directory.CreateDirectory(m_result_path);
        }

        ExportBundleTxt();

        ExportAssetTxt();

        OnFinish?.Invoke(m_result_path);
    }

    private void ExportBundleTxt()
    {
        string path = string.Format("{0}/Bundle.txt", m_result_path);

        var m_sw = new StreamWriter(path);

        m_sw.WriteLine($"Index,Bundle.Name,Tags,Bundle.Size,Asset.Num,Asset.Types");

        int cnt = 0;
        foreach (var pair in mBundleMap)
        {
            int index = cnt++;
            string bunle_name = pair.Key;
            string tags = GetTagsByBundleName(bunle_name);
            long size = GetBundleSize(bunle_name);
            int asset_num = pair.Value.Count;
            string asset_types = GetAssetTypes(pair.Value);

            m_sw.WriteLine($"{index},{bunle_name},{tags},{size},{asset_num},{asset_types}");
        }

        m_sw.Flush();
        m_sw.Close();

        Debug.Log("BundleTxt Complete");
    }

    private void ExportAssetTxt()
    {
        string path = string.Format("{0}/Asset.txt", m_result_path);

        var m_sw = new StreamWriter(path);

        m_sw.WriteLine($"Index,Bundle.Name,Asset.Name");

        int cnt = 0;
        foreach (var pair in mBundleMap)
        {
            string bunle_name = pair.Key;

            foreach (var asset_name in pair.Value)
            {
                m_sw.WriteLine($"{cnt++},{bunle_name},{asset_name}");
            }
        }

        m_sw.Flush();
        m_sw.Close();

        Debug.Log("AssetTxt Complete");

    }

    private string GetTagsByBundleName(string name)
    {
        return name.ToLower().Replace("_formal/", "").Replace("/", " ").ToUpper();
    }

    private long GetBundleSize(string name)
    {

        string filePath = Path.Combine(m_ab_path, name);

        if (File.Exists(filePath) == false)
        {
            return 0;
        }

        FileInfo fi = new FileInfo(filePath);
        return fi.Length;
    }

    private string GetAssetTypes(HashSet<string> assets)
    {
        string result = string.Empty;
        HashSet<string> result_set = new HashSet<string>();
        foreach (var item in assets)
        {
            FileInfo fi = new FileInfo(item);
            result_set.Add(fi.Extension);
        }
        result = string.Join("|", result_set.ToList());
        return result;
    }

    private void ClearAssets()
    {
        mBundleMap.Clear();
        mBundleMap = null;
        Resources.UnloadUnusedAssets();
        EditorUtility.UnloadUnusedAssetsImmediate();
        GC.Collect();
    }

    private AssetBundle LoadAB(string path)
    {
        return AssetBundle.LoadFromFile(path);
    }

    private bool GenAssetMap(string path, string maniFest)
    {
        path = path.Replace("\\", "/");
        AssetBundle maniFestAb = LoadAB(Path.Combine(path, maniFest));
        if (maniFestAb == null)
            return false;

        AssetBundleManifest manifest = maniFestAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        if (manifest == null)
            return false;

        string[] allBundles = manifest.GetAllAssetBundles();
        maniFestAb.Unload(true);
        foreach (string abName in allBundles)
        {
            string filePath = Path.Combine(path, abName);
            AssetBundle ab = LoadAB(filePath);

            if (mBundleMap.ContainsKey(abName) == false)
            {
                mBundleMap[abName] = new HashSet<string>();
            }
            var asset_set = mBundleMap[abName];

            try
            {
                foreach (string asset in ab.GetAllAssetNames())
                {
                    asset_set.Add(asset);
                }

                foreach (string asset in ab.GetAllScenePaths())
                {
                    asset_set.Add(asset);
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                ab.Unload(true);
            }
        }

        if (mBundleMap.Count == 0)
            return false;

        return true;
    }

    private List<string> GetAllFiles(List<string> files, string folder)
    {
        folder = folder.Replace("\\", "/");
        DirectoryInfo dir = new DirectoryInfo(folder);
        foreach (var file in dir.GetFiles("*.*"))
        {
            if (file.Extension == ".manifest")
            {
                continue;
            }
            if (Utils.File.GetRegularPath(file.FullName.ToLower()) == Utils.File.GetRegularPath(m_ab_path.ToLower()))
            {
                continue;
            }
            files.Add((Path.Combine(folder, file.Name).Replace("\\", "/")).ToLower());
        }

        foreach (var sub in dir.GetDirectories())
        {
            files = GetAllFiles(files, Path.Combine(folder, sub.Name));
        }

        return files;
    }

}
